
#include <stdio.h>
#include "lg_canvas.h"

#define LGOGL_CORE

#include "lgogl_canvas.h"
#include "lgogl_texture.h"
#include "lgogl_draw.h"
#include "lgogl_window.h"

static struct {
	LGCanvas* curBind;
}gCtx = { 0 };


static size_t
sizeofCanvas(){
	return sizeof(LGOGLCanvas);
}

static int
newCanvas(LGCanvas* canvas) {
	LGOGLCanvas* oglCanvas = (LGOGLCanvas*)canvas;
	glGenFramebuffers(1, &oglCanvas->fbo);
	glBindFramebuffer(GL_FRAMEBUFFER, oglCanvas->fbo);
	glGenTextures(1, &oglCanvas->colorTex);
	glBindTexture(GL_TEXTURE_2D, oglCanvas->colorTex);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 
		canvas->width, canvas->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glFramebufferTexture2D(GL_FRAMEBUFFER,
		GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, oglCanvas->colorTex, 0);

	glGenTextures(1, &oglCanvas->depthTex);
	glBindTexture(GL_TEXTURE_2D, oglCanvas->depthTex);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8,
		canvas->width, canvas->height, 0,
		GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
	glFramebufferTexture2D(GL_FRAMEBUFFER,
		GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, oglCanvas->depthTex, 0);

	glGenRenderbuffers(1, &oglCanvas->rbo);
	glBindRenderbuffer(GL_RENDERBUFFER, oglCanvas->rbo);
	glRenderbufferStorage(GL_RENDERBUFFER,
		GL_DEPTH24_STENCIL8, canvas->width, canvas->height);
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindRenderbuffer(GL_RENDERBUFFER, 0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	return 0;
}

static int
newWindowCanvas(LGCanvas* canvas) {
	LGOGLCanvas* oglCanvas = (LGOGLCanvas*)canvas;
	oglCanvas->fbo = 0;
	oglCanvas->rbo = 0;
	oglCanvas->colorTex = 0;
	oglCanvas->depthTex = 0;
	return 0;
}

static void
freeCanvas(LGCanvas* canvas) {
	LGOGLCanvas* oglCanvas = (LGOGLCanvas*)canvas;
	if (gCtx.curBind == canvas) {
		lgoglBindCanvas(NULL);
	}
	glDeleteTextures(1, &oglCanvas->colorTex);
	glDeleteTextures(1, &oglCanvas->depthTex);
	glDeleteRenderbuffers(1, &oglCanvas->rbo);
	glDeleteFramebuffers(1, &oglCanvas->fbo);
}

static void
clearCanvas(LGCanvas* canvas) {
	LGOGLCanvas* oglCanvas = (LGOGLCanvas*)canvas;
	lgoglBindCanvas(canvas);
	glBindFramebuffer(GL_FRAMEBUFFER, oglCanvas->fbo);
	glBindTexture(GL_TEXTURE_2D, oglCanvas->colorTex);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
		canvas->width, canvas->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glBindTexture(GL_TEXTURE_2D, oglCanvas->depthTex);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8,
		canvas->width, canvas->height, 0,
		GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
	LGVector color = canvas->color;
	glViewport(0, 0, canvas->width, canvas->height);
	glDepthMask(GL_TRUE);
	glClearColor((GLfloat)color.x, (GLfloat)color.y,
		(GLfloat)color.z, (GLfloat)color.w);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//glDepthMask(GL_FALSE);
	glBindTexture(GL_TEXTURE_2D, 0);
}

static void
renderCanvas(LGCanvas* canvas) {
	//lgoglBindCanvas(canvas);
	//LGOGLCanvas* oglCanvas = (LGOGLCanvas*)canvas;
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//LGVector color = canvas->color;
	//glClearColor((GLfloat)color.x, (GLfloat)color.y,
	//	(GLfloat)color.z, (GLfloat)color.w);

	//lgClearCanvas(canvas);
	//glViewport(0, 0, canvas->width, canvas->height);

	//glBindTexture(GL_TEXTURE_2D, oglCanvas->colorTex);
	//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
	//	canvas->width, canvas->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	//glBindTexture(GL_TEXTURE_2D, oglCanvas->depthTex);
	//glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8,
	//	canvas->width, canvas->height, 0,
	//	GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
	//glBindTexture(GL_TEXTURE_2D, 0);
	//GLint err = glGetError();
	//if (err) {
	//	printf("renderCanvas err:%d\n", err);
	//}
}

static LGCanvasBackend backend = {
	sizeofCanvas,
	newCanvas,
	newWindowCanvas,
	freeCanvas,
	clearCanvas,
	renderCanvas,
};

LGOGL_API LGCanvasBackend*
lgoglCanvasBackend() {

	return &backend;
}

LGOGL_API void
lgoglBindCanvas(LGCanvas* canvas) {
	if (canvas == gCtx.curBind) {
		return;
	}
	gCtx.curBind = canvas;
	if (canvas) {
		LGOGLCanvas* oglCanvas = (LGOGLCanvas*)canvas;
		glBindFramebuffer(GL_FRAMEBUFFER, oglCanvas->fbo);
	}
	else {
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
	}
}


LGOGL_API GLuint
lgoglGetCanvasTexId(LGCanvas* canvas) {
	return ((LGOGLCanvas*)canvas)->colorTex;
}